package com.zq.vaccinum.config;

import com.zq.vaccinum.filter.JwtAuthFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * SpringSecurity配置类
 * @Author: zq
 * @Date: 2023/08/04/2:14
 * @Description:
 */
@Configuration
@EnableWebSecurity // 添加 security 过滤器
@EnableGlobalMethodSecurity(prePostEnabled = true)	// 启用方法级别的权限认证
public class SpringSecurityConfig {
    /*
    * 用户密码加密工具，注入容器
    * $2a(bcrypt加密版本号)$10(cost的值) 加密方式+ 盐(22位) + 密文
    * $2a$10xxxxx/xxxxx/xxxx
    * */

    @Autowired
    private AuthenticationConfiguration authenticationConfiguration;

    @Autowired
    private JwtAuthFilter jwtAuthFilter;

    // 认证异常处理
    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;
    // 授权异常处理
    @Autowired
    private AccessDeniedHandler accessDeniedHandler;

    /**
     * 获取AuthenticationManager（认证管理器），登录时认证使用
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager getAuthenticationManagerBean() throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    /**
     * 用户密码加密方式配置
     * @return
     */
    @Bean
    public PasswordEncoder getPasswordEncoderBean(){
        return new BCryptPasswordEncoder();
    }

    /**
     * 配置类
     * @param http
     * @return
     */
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                // 基于 token，不需要 csrf
                .csrf().disable()
                // 基于 token，不需要 session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                // 下面开始设置权限
                .authorizeRequests(authorize -> authorize
                        // 请求,允许匿名访问(登录后不能访问)
                        .antMatchers("/user/login").anonymous()
                        .antMatchers("/user/register").anonymous()
                        .antMatchers("/captcha/*").permitAll()
//                        .antMatchers("/vaccinum-type/list").permitAll()
                        // 其他地址的访问均需验证权限
                        .anyRequest().authenticated()
                )
                // 在 UsernamePasswordAuthenticationFilter.class 过滤器之前
                // 添加 JWT 过滤器，JWT 过滤器在用户名密码认证过滤器之前
                .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
//                // 认证用户时用户信息加载配置，注入springAuthUserService
//                .userDetailsService(userDetailsService)
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler)
                .and()
                .cors()     // 允许跨域访问
                .and()
                .build();
    }
    /**
     * 配置跨源访问(CORS)
     * @return
     */
//    @Bean
//    CorsConfigurationSource corsConfigurationSource() {
//        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
//        return source;
//    }
}
